﻿// 性能回归测试工具
#if ENABLE_ET_COM
namespace suite_effciency_regression
{
    using System;
    using System.Xml;
    using System.Collections.Generic;

    public enum EffType
    {
        MATRIXPLUS  = 0,
        STATUSBAR   = 2,
        ROWHEIGHT   = 3,
        BORDER      = 4,
        SHRFMLA     = 5,
    }

    internal class CRange
    {
        public CRange(string sC1, string sC2)
        {
            Cell1 = sC1;
            Cell2 = sC2;
        }
        // 左上角
        public string Cell1 { set; get; }
        //右下角
        public string Cell2 { set; get; }
    }

    public class CEffReg : suit_base.SuiteBase
    {
        protected class CFileItem
        {
            public string FileName { set; get; }
            public int ExpTime { set; get; }

            public CFileItem(string _fileName, int _expTm)
            {
                FileName = _fileName;
                ExpTime = _expTm;
            }
        }
        List<CFileItem> m_matrixplsuLst;
        List<CFileItem> m_shrfmlaLst;

        private string m_sEt;
        private const string EXP_FILENAME = "exp_effreg.xml";
        XmlDocument m_expDoc;
        XmlElement m_rootNode;

        private List<CRange> m_statusbarRg;
        private List<CRange> m_rowheightRg;
        private List<CRange> m_borderRg;
        private const int m_nStatusbarTm = 6;
        private const int m_nRowheightTm = 6;
        private const int m_nBorderTm = 9;

        public override string GetCommand()
        {
            return ET_Improve.Global.CMD_EFFREG;
        }

        public override void Call()
        {
            try
            {
                LoadConfig();
                InitRange();
                tool.LogTool.GetInstance().BeginUseLog(null, ET_Improve.Global.s_curCmdName);
                etOp.EtOp.ReRegisterET(m_sEt);

                BeginExpFile();
                DoMatrixPlus();
                DoShrFmla();
                DoFileIndependent();
                SaveExpFile();
            }
            catch (tool.ETImpException ex)
            {
                ex.AddLog();
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, null, 
                    ET_Improve.Global.s_curCmdName + " 失败", ex);
            }
            finally
            {
                tool.LogTool.GetInstance().EndUseLog();
            }
        }

        void LoadConfig()
        {
            const string LOG_ROOT = "EffRegression";
            const string LOG_ETPATH = "EtPath";
            const string LOG_MATRIXPLUS = "Matrixplus";
            const string LOG_SHRFMLA = "Shrfmla";
            try
            {
                m_matrixplsuLst = new List<CFileItem>();
                m_shrfmlaLst = new List<CFileItem>();
                foreach (XmlNode subNode in tool.ConfigReader.GetElementList(LOG_ROOT))
                {
                    if (subNode.Name == LOG_ETPATH)
                    {
                        m_sEt = subNode.InnerText;
                    }
                    else if (subNode.Name == LOG_MATRIXPLUS)
                    {   
                        LoadTestFile(subNode, m_matrixplsuLst);
                    }
                    else if (subNode.Name == LOG_SHRFMLA)
                    {
                        LoadTestFile(subNode, m_shrfmlaLst);
                    }
                }
            }
            catch (System.Exception ex)
            {
                tool.Output.DumpWriteLine(ex.ToString());
                throw ex;
            }
        }

        protected void BeginExpFile()
        {
            try
            {
                m_expDoc = new XmlDocument();
                XmlDeclaration xmlDec = m_expDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
                m_expDoc.InsertBefore(xmlDec, m_expDoc.DocumentElement);
                m_rootNode = m_expDoc.CreateElement("", "root", "");
                m_expDoc.AppendChild(m_rootNode);

                XmlComment comment = m_expDoc.CreateComment(tool.CTimer.GetTimeComment());
                m_rootNode.AppendChild(comment);
            }
            catch (System.Exception ex)
            {
            	throw ex;
            }
        }

        protected void SaveExpFile()
        {
            try
            {
                string sDst = ET_Improve.Global.m_strDefaultDir;
                tool.CAddInfoHlp.ValidDirectory(ref sDst);
                sDst += EXP_FILENAME;
                m_expDoc.Save(sDst);
            }
            catch (System.Exception ex)
            {
            	throw ex;
            }
        }

        void LoadTestFile(XmlNode rootNode, List<CFileItem> lst)
        {
            const string LOG_FILENAME   = "FileName";
            const string LOG_EXPET_TM   = "ExpectTime";
            XmlNodeList xnl = rootNode.ChildNodes;
            foreach (XmlNode node in xnl)
            {
                XmlElement xe = (XmlElement)node;
                if (xe.Name == "File")
                {
                    lst.Add( new CFileItem(
                        xe.GetAttribute(LOG_FILENAME),
                        int.Parse(xe.GetAttribute(LOG_EXPET_TM))));
                }
            }
        }

        protected void InitRange()
        {
            // 添加要测试的range
            CRange rg1 = new CRange("A1", "IV65536");
            CRange rg2 = new CRange("C10", "H100");
            CRange rg3 = new CRange("A5000", "A65536");
            CRange rg4 = new CRange("IV1", "IV65536");
            CRange rg5 = new CRange("A500", "A2500");
            m_statusbarRg = new List<CRange>();
            m_statusbarRg.Add(rg1);
            m_statusbarRg.Add(rg2);
            m_statusbarRg.Add(rg1);
            m_statusbarRg.Add(rg2);
            m_statusbarRg.Add(rg3);
            m_statusbarRg.Add(rg4);
            m_statusbarRg.Add(rg5);

            m_rowheightRg = new List<CRange>(m_statusbarRg);

            m_borderRg = new List<CRange>();
            m_borderRg.Add(rg2);
            m_borderRg.Add(rg1);
            m_borderRg.Add(rg5);
            m_borderRg.Add(rg3);
        }

        protected void AddExpFile(EffType _type, int nExpTm, double dUsedTm)
        {
            try
            {
                XmlElement node = m_expDoc.CreateElement("", _type.ToString(), "");
                node.SetAttribute("ExpectTime", string.Format("{0}", nExpTm) );
                node.SetAttribute("UsedTime", string.Format("{0}", dUsedTm));
                m_rootNode.AppendChild(node);
            }
            catch (System.Exception ex)
            {
	            throw ex;
            }
        }

        // 只求打开时间就行
        protected void DoMatrixPlus()
        {
            string sCurFile = null;
            try
            {
                foreach (CFileItem item in m_matrixplsuLst)
                {
                    CET pET = new CET(item.FileName, item.ExpTime);
                    AddExpFile(EffType.MATRIXPLUS, item.ExpTime, pET.GetUsedTime(EffType.MATRIXPLUS, null) );
                }
            }
            catch(tool.ETImpException ex)
            {
                ex.AddLog();
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, sCurFile, 
                    EffType.MATRIXPLUS.ToString(), ex);
            }
        }

        protected void DoShrFmla()
        {
            string sCurFile = null;
            try
            {
                foreach (CFileItem item in m_shrfmlaLst)
                {
                    CET pET = new CET(item.FileName, item.ExpTime);
                    AddExpFile( EffType.SHRFMLA, item.ExpTime, pET.GetUsedTime(EffType.SHRFMLA, null) );
                }
            }
            catch (tool.ETImpException ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());
                ex.AddLog();
            }
            catch (System.Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, sCurFile, 
                    EffType.SHRFMLA.ToString(), ex);
            }
        }

        protected void DoFileIndependent()
        {
            try
            {
                CET pEt1 = new CET(null, m_nRowheightTm);
                AddExpFile(EffType.ROWHEIGHT, m_nRowheightTm, pEt1.GetUsedTime(EffType.ROWHEIGHT, m_rowheightRg));
                pEt1 = null;

                CET pEt2 = new CET(null, m_nStatusbarTm);
                AddExpFile(EffType.STATUSBAR, m_nStatusbarTm, pEt2.GetUsedTime(EffType.STATUSBAR, m_statusbarRg));
                pEt2 = null;

                CET pEt3 = new CET(null, m_nBorderTm);
                AddExpFile(EffType.BORDER, m_nBorderTm, pEt3.GetUsedTime(EffType.BORDER, m_borderRg));
                pEt3 = null;
            }
            catch (tool.ETImpException ex)
            {
                ex.AddLog();
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, null,
                    "性能回归 - 文件无关测试", ex);
            }
        }

        public static bool IsAllAlpha(string str)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(str, "[a-zA-Z]");
        }

        public static bool IsAllNumber(string str)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(str, "[0-9]");
        }
    }

    class CET : etOp.EtOp
    {
        private tool.CTimer m_checkClock;
        private int m_nExpTime;
        public CET(string _sFileName, int _expTm)
        {
            m_sCurFileName = _sFileName;
            m_nExpTime = _expTm;
            m_checkClock = new tool.CTimer(CheckCPU);
        }

        public double GetUsedTime(EffType _type, List<CRange> lstRg)
        {
            double dUsedTm = -1;
            try
            {
                m_checkClock.BeginTimer(7, true); //7秒检查一次
                DateTime dt1 = DateTime.Now;
                if (!IsDoneSomething(_type, lstRg) || m_checkClock.IsTimeOut())
                {
                    m_checkClock.EndTimer();
                    return dUsedTm;
                }

                DateTime dt2 = DateTime.Now;
                TimeSpan spanTm = dt2 - dt1;
                dUsedTm = spanTm.TotalSeconds;
                m_checkClock.EndTimer();
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, m_sCurFileName,
                    "Failed of GetUsedTime", ex);
            }
            return dUsedTm;
        }

        protected bool IsDoneSomething(EffType _type, List<CRange> lstRg)
        {
            bool bRet = true;
            switch (_type)
            {
                case EffType.MATRIXPLUS:
                    bRet = DoMatrixPlus();
                    break;
                case EffType.SHRFMLA:
                    bRet = DoShrfmla();
                    break;
                case EffType.ROWHEIGHT:
                    bRet = DoRowHeight(lstRg);
                    break;
                case EffType.STATUSBAR:
                    bRet = DoStatusBar(lstRg);
                    break;
                case EffType.BORDER:
                    bRet = DoBorder(lstRg);
                    break;
            }
            return bRet;
        }

        protected bool DoMatrixPlus()
        {
            bool bRet = false;
            try
            {
                Open(m_sCurFileName, null);
                bRet = true;
            }
            catch (tool.ETImpException ex)
            {
                ex.AddLog();
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, m_sCurFileName,
                    ">Opend failed!<", ex);
            }
            finally
            {
                Close();
            }
            return bRet;
        }

        protected bool DoShrfmla()
        {
            bool bRet = false;
            try
            {
                Open(m_sCurFileName, null);
                ET.Worksheets _worksheets = m_app.Worksheets;
                ET.Worksheet etSheet1 = (ET.Worksheet)_worksheets[1];
                ET.Range etRg = etSheet1.get_Range("A1:IV65536", Type.Missing);
                etRg.AutoFilter(15, "=*民治*", ET.ETAutoFilterOperator.etAnd,
                    Type.Missing, Type.Missing);
                etRg = etSheet1.get_Range("A3:IV30000", Type.Missing);
                etRg.Select();
                etRg.EntireRow.Delete(ET.ETDeleteShiftDirection.etShiftUp);
                NAR(etRg);
                NAR(etSheet1);
                NAR(_worksheets);
                bRet = true;
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, m_sCurFileName,
                    ">Failed of DoShrfmla<", ex);	      	
            }
            return bRet;
        }

        protected bool DoRowHeight(List<CRange> lstRg)
        {
            bool bRet = false;
            try
            {
                Create();
                m_app.Visible = true;
                ET.Worksheets _worksheets = m_app.Worksheets;
                ET.Worksheet etSheet1 = (ET.Worksheet)_worksheets[1];
                foreach (CRange rg in lstRg)
                {
                    ET.Range etRg = etSheet1.get_Range(rg.Cell1, rg.Cell2);
                    etRg.Select();
                    Random rd = new Random(GetRandomSeed());
                    int nHeight = rd.Next(3, 30);
                    etRg.RowHeight = nHeight;
                    tool.Output.DumpWriteLine(rg.Cell1 + "/" + rg.Cell2 + " height=" + nHeight.ToString());
                    NAR(etRg);
                }
                NAR(etSheet1);
                NAR(_worksheets);
                bRet = true;
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, m_sCurFileName,
                    "Failed of DoRowHeight", ex);
            }
            finally
            {
                Close();
            }
            return bRet;
        }

        protected bool DoBorder(List<CRange> lstRg)
        {
            bool bRet = false;
            try
            {
                Create();
                m_app.Visible = true;
                ET.Worksheets _worksheets = m_app.Worksheets;
                ET.Worksheet etSheet1 = (ET.Worksheet)_worksheets[1];
                foreach (CRange rg in lstRg)
                {
                    ET.Range etRg = etSheet1.get_Range(rg.Cell1, rg.Cell2);
                    etRg.Activate();
                    etRg.Borders.LineStyle = GetRandomLineStyle();
                    etRg.BorderAround(GetRandomLineStyle(), ET.ETBorderWeight.etHairline, ET.ETColorIndex.etColorIndexNone, null);
                    System.Diagnostics.Debug.WriteLine("LineStyle:" + etRg.Borders.LineStyle.ToString());
                    NAR(etRg);
                }
                NAR(etSheet1);
                NAR(_worksheets);
                bRet = true;
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, m_sCurFileName,
                    "Failed of DoBorder", ex);
            }
            finally
            {
                Close();
            }
            return bRet;
        }

        protected ET.ETLineStyle GetRandomLineStyle()
        {
            Random rd = new Random(GetRandomSeed());
            int nIndex = rd.Next(1, 7);
            ET.ETLineStyle lineSty = ET.ETLineStyle.etLineStyleNone;
            switch (nIndex)
            {
                case 0: lineSty = ET.ETLineStyle.etLineStyleNone; break;
                case 1: lineSty = ET.ETLineStyle.etDouble; break;
                case 2: lineSty = ET.ETLineStyle.etDot; break;
                case 3: lineSty = ET.ETLineStyle.etDash; break;
                case 4: lineSty = ET.ETLineStyle.etContinuous; break;
                case 5: lineSty = ET.ETLineStyle.etDashDot; break;
                case 6: lineSty = ET.ETLineStyle.etDashDotDot; break;
                case 7: lineSty = ET.ETLineStyle.etSlantDashDot; break;
            }
            return lineSty;
        }

        protected bool DoStatusBar(List<CRange> lstRg)
        {
            tool.Output.DumpWriteLine(">>Begin DoStatusBar>");
            bool bRet = false;
            try
            {
                Create();
                m_app.Visible = true;
                ET.Worksheets _worksheets = m_app.Worksheets;
                ET.Worksheet etSheet1 = (ET.Worksheet)_worksheets[1];
                foreach (CRange rg in lstRg)
                {
                    ET.Range etRg = etSheet1.get_Range(rg.Cell1, rg.Cell2);
                    tool.Output.DumpWriteLine(string.Format("range: {0}:{1}", rg.Cell1, rg.Cell2));
                    etRg.Select();
                    TestDisplay();
                    NAR(etRg);
                }
                NAR(etSheet1);
                NAR(_worksheets);
                bRet = true;
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, m_sCurFileName,
                    "Failed of DoStatusBar:", ex);
            }
            finally
            {
                Close();
                tool.Output.DumpWriteLine(">>End DoStatusBar<");
            }
            return bRet;
        }

        protected void TestDisplay()
        {
            try
            {
                if(m_app == null)
                {
                    Console.WriteLine(">>>m_app == null<<<");
                }
//                 string sVal = m_app.SmartTip;
//                 if (sVal != null)
//                 {
//                     tool.Output.DumpWriteLine(sVal);
//                 }
//                 else
//                 {
//                     tool.Output.DumpWriteLine(">>>NULL<<<");
//                 }
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(">>>SmartTip错误<<<");
                Console.WriteLine(ex.ToString());
            }
        }

        protected int GetRandomSeed()
        {
            byte[] bytes = new byte[4];
            System.Security.Cryptography.RNGCryptoServiceProvider rng =
                new System.Security.Cryptography.RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }

        protected void SetTestValue()
        {
            try
            {
                ET.Worksheets _worksheets = m_app.Worksheets;
                ET.Worksheet _worksheet = (ET.Worksheet)_worksheets[1];
                ET.Range etRg1 = _worksheet.get_Range("A1", "A65536");
                etRg1.Value2 = "1";

                ET.Range etRg2 = _worksheet.get_Range("IV1", "IV65536");
                etRg2.Value2 = "1";

                ET.Range etRg3 = _worksheet.get_Range("C1", "K65536");
                etRg3.Value2 = "1";

                NAR(etRg1);
                NAR(etRg2);
                NAR(etRg3);
                NAR(_worksheet);
                NAR(_worksheets);
            }
            catch (System.Exception ex)
            {
                throw ex;
            }
        }

        protected void CheckCPU()
        {
            double dCurTm = GetCpuTime();
            tool.Output.DumpWriteLine(string.Format("CPU:{0} \nexpTm:{1}", dCurTm, m_nExpTime));
            if (dCurTm > m_nExpTime)
            {
                tool.Output.DebugWriteLine(">time unaccepted<");
                KillCurApp();
                return;
            }
            m_checkClock.SetTimerFlagRun();
        }

        protected double GetCpuTime()
        {
            try
            {
                System.Diagnostics.Process proc =
                    System.Diagnostics.Process.GetProcessById(m_nCurEtPid);
                return proc.TotalProcessorTime.TotalSeconds;
            }
            catch (System.Exception ex)
            {
                tool.Output.DumpWriteLine("GetCpuTime failed:" + ex.Message);
                return -1;
            }
        }
    }
}
#endif // #if ENABLE_ET_COM